package com.fulihui.information.service;

import com.fulihui.information.api.StarService;
import com.fulihui.information.biz.content.FullDateManager;
import com.fulihui.information.biz.counter.ContentStarTimesOperableCounter;
import com.fulihui.information.core.repository.ContentRepository;
import com.fulihui.information.dal.dataobj.InfoContentUserStar;
import com.fulihui.information.dal.dataobj.InfoContentUserStarExample;
import com.fulihui.information.dal.mapper.ExtInfoContentUserStarMapper;
import com.fulihui.information.dal.mapper.InfoContentUserStarMapper;
import com.fulihui.information.dto.ContentListItemDTO;
import com.fulihui.information.model.UserContentOperate;
import com.fulihui.information.request.IsStarQueryRequest;
import com.fulihui.information.request.UserStarQueryPageRequest;
import com.fulihui.information.request.UserStarRequest;
import org.apache.dubbo.config.annotation.Service;
import org.near.servicesupport.error.Errors;
import org.near.servicesupport.result.BaseResult;
import org.near.servicesupport.result.TPageResult;
import org.near.servicesupport.result.TSingleResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import static org.near.servicesupport.result.ResultBuilder.*;
import static org.springframework.util.CollectionUtils.isEmpty;

/**
 * @author Willard.Hu on 2017/1/5 0005.
 */
@Service(version = "1.0.0")
public class StarServiceImpl implements StarService {
    @Autowired
    private InfoContentUserStarMapper       infoContentUserStarMapper;
    @Autowired
    private ExtInfoContentUserStarMapper    extInfoContentUserStarMapper;
    @Autowired
    private ContentRepository               contentRepository;
    @Autowired
    private ContentStarTimesOperableCounter contentStarTimesOperableCounter;
    @Autowired
    private FullDateManager                 fullDateManager;

    /**
     * @see StarService#star(UserStarRequest)
     */
    @Override
    @Transactional
    public BaseResult star(UserStarRequest request) {
        InfoContentUserStar record = new InfoContentUserStar();
        record.setUserId(request.getUserId());
        record.setContentId(request.getContentId());

        InfoContentUserStarExample example = new InfoContentUserStarExample();
        example.createCriteria().andUserIdEqualTo(request.getUserId())
                .andContentIdEqualTo(request.getContentId());
        List<InfoContentUserStar> list = infoContentUserStarMapper.selectByExample(example);
        // 已收藏不能重复再收藏
        if (!isEmpty(list)) {
            return fail(Errors.Commons.SYSTEM_ERROR);
        }
        infoContentUserStarMapper.insert(record);

        UserContentOperate operate = new UserContentOperate();
        operate.setContentId(request.getContentId());
        contentStarTimesOperableCounter.operate(operate);

        return succ();
    }

    /**
     * @see StarService#unstar(UserStarRequest)
     */
    @Override
    @Transactional
    public BaseResult unstar(UserStarRequest request) {
        InfoContentUserStarExample example = new InfoContentUserStarExample();
        example.createCriteria()
                .andUserIdEqualTo(request.getUserId())
                .andContentIdEqualTo(request.getContentId());
        int rs = infoContentUserStarMapper.deleteByExample(example);
        // 删除无效直接返回失败
        if (rs == 0) {
            return fail(Errors.Commons.SYSTEM_ERROR);
        }

        UserContentOperate operate = new UserContentOperate();
        operate.setContentId(request.getContentId());
        operate.setNum(-1);
        contentStarTimesOperableCounter.operate(operate);

        return rs > 0 ? succ() : fail(Errors.Commons.SYSTEM_ERROR);
    }

    /**
     * @see StarService#userStars(UserStarQueryPageRequest)
     */
    @Override
    public TPageResult<ContentListItemDTO> userStars(UserStarQueryPageRequest request) {
        InfoContentUserStarExample example = new InfoContentUserStarExample();
        example.createCriteria()
                .andUserIdEqualTo(request.getUserId());
        example.setOrderByClause(request.getOrderByClause());
        List<InfoContentUserStar> userStars = extInfoContentUserStarMapper.selectByPageExample(example,
                request.start4Mysql(), request.getRows());
        if (isEmpty(userStars)) {
            return succTPage(Collections.emptyList(), request.getPage(), request.getRows(), 0);
        }
        List<String> ids = userStars.stream()
                .map(InfoContentUserStar::getContentId)
                .collect(Collectors.toList());
        List<ContentListItemDTO> list = contentRepository.queryItemListByIds(ids);
        // in查询获取的顺序不一定是结果的顺序，需要再次排序
        int i = 0;
        for (String id : ids) {
            int idx = indexOf(list, id, i);
            if (idx >= 0 && idx != i) {
                swap(list, i, idx);
            }
            i++;
        }
        fullDateManager.fullMulti(list);
        int count = (int) infoContentUserStarMapper.countByExample(example);
        return succTPage(list, request.getPage(), request.getRows(), count);
    }

    /**
     * @see StarService#isStar(IsStarQueryRequest)
     */
    @Override
    public TSingleResult<Boolean> isStar(IsStarQueryRequest request) {
        InfoContentUserStarExample example = new InfoContentUserStarExample();
        example.createCriteria().andContentIdEqualTo(request.getContentId())
                .andUserIdEqualTo(request.getUserId());
        List<InfoContentUserStar> userStar = infoContentUserStarMapper.selectByExample(example);
        return succTSingle(!isEmpty(userStar));
    }

    private void swap(List<ContentListItemDTO> list, int i, int j) {
        ContentListItemDTO temp = list.get(i);
        list.set(i, list.get(j));
        list.set(j, temp);
    }

    private int indexOf(List<ContentListItemDTO> list, String id, int start) {
        for (int i = start, size = isEmpty(list) ? 0 : list.size(); i < size; i++) {
            if (list.get(i).getId().equals(id)) {
                return i;
            }
        }
        return -1;
    }

}
